﻿#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <vector>
#include <queue>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <unordered_map>
/*using namespace std;

! THREADPOOL_H*/

//类： Task类  Thread类 ThreadPool类
//  Task 类 成员变量：
// Thread类 成员变量：func_
// ThreadPool类 成员变量  initThreadSize_ taskQueMaxThreadHold_ 
//任务抽象基类
/*用 template<typename T> 定义 Derive<T>，让它能存储任意类型 T 的 data_。
Any 类通过 template<typename T> 的构造函数，
把任意类型 T 的数据，用 Derive<T> 包装后存起来。
再通过 template<typename T> 的 cast_<T>() 函数，
按指定类型 T 把数据取出来（用 dynamic_cast 做类型校验 ）。
****
* Any 是 “万能收纳盒”，
base_ 是 “统一隔层”，
Derive<T> 是 “定制小盒子”，
template<typename T> 是 “万能标签”，
std::make_unique 是 “造小盒子并装东西” 的动作。

你想存一个 int 数据（比如 data=100 ）：
代码触发 Any(100) → 因为存的是 int，所以 T=int。
第一步：template<typename T> 贴上 “T=int” 的标签。
第二步：Derive<T> 变成 Derive<int> → 取到这个标签，生成一个专门装 int 的 “小盒子”。
第三步：std::make_unique<Derive<int>>(100) → 用小盒子装 100，然后交给 base_ 统一管理。
结果：收纳盒 Any 里，通过 base_ 存了一个装着 100 的 Derive<int> 小盒子。


*/
class Any
{
public:
	Any() = default;//使用默认构造函数
	~Any() = default;
	Any(const Any&) = delete; //禁止拷贝构造
	Any& operator=(const Any&) = delete;//禁止拷贝赋值
	Any(Any&&) = default;//允许移动构造（用默认逻辑）把一个 Any 对象的 “资源所有权”转移给另一个对象
	Any& operator=(Any&&) = default;//“允许移动赋值（用默认逻辑）”

	// 这个构造函数可以让Any类型接收任意其它的数据
	template<typename T>  // T:int    Derive<int>
	Any(T data) : base_(std::make_unique<Derive<T>>(data))
	{}

	 /* template<typename T> T cast_() 函数，
	 会通过 运行时类型识别,把 base_ 指向的 Derive<T> 
	对象找出来，然后返回内部存储的 data_，
	完成 “存任意类型、取指定类型” 的流程*/
	//这个方法可以把Any对象存储的data数据数据提取出来
	template<typename T>
	T cast_()
	{
		// 我们怎么从base_找到它所指向的Derive对象，从它里面取出data成员变量
		// 基类指针 =》 派生类指针   RTTI  dynamic_cast 是 C++ 的动态类型转换运算符
		//尝试把 base_.get() 得到的 Base* 指针，转换成 Derive<T>* 类型的指针”,
		//指针 pd，用来存储转换后的结果
		/*你用 Any 存了一个 int 类型，内部实际是 Derive<int> 对象，
		存在 base_ 里（Base* 类型 ）。
        取数据时，调用 cast_<int>()，这行代码会尝试把 base_ 转换成 Derive<int>*：
        转换成功 → 通过 pd->data_ 拿到 int 数据。
        转换失败 → 抛异常（比如你存的是 int，却用 cast_<string>() 取 ）*/
		Derive<T>* pd = dynamic_cast<Derive<T>*>(base_.get());
		if (pd == nullptr)
		{
			throw "type is unmatch!";
		}
		return pd->data_;
	}
private:
	// 基类类型
	/*基类 Base，作为统一接口，
	让 Derive<T> 继承后，能用 Base 指针（这里是 std::unique_ptr<Base> ）
	存储不同 Derive<T> 类型的对象，实现多态。*/
	class Base  
	{
	public:
		virtual ~Base() = default;
	};

	// 派生类类型
	template<typename T>
	class Derive : public Base
	{
	public:
		/*Derive 是一个模板类，因为用到了模板参数 T ），
		data_ 是 Derive 类的一个成员变量
		（类型通常会和 T 适配，比如 T data_; 这样在类里声明 ）。
		构造函数 Derive 接收一个 T 类型的参数 data，
		然后通过初始化列表 : data_(data) ，
		使用传入的 data 的值来初始化成员变量 data_ 。
		这种初始化方式相比在构造函数体内赋值（如 data_ = data; ）*/
		Derive(T data) : data_(data)
		{}
		T data_;  // 保存了任意的其它类型
	private:
		//T data_;  // 保存了任意的其它类型
	};

private:
	// 定义一个基类的指针
	std::unique_ptr<Base> base_;
};

//实现一个信号量
class Semaphore
{
public:
	Semaphore(int limit = 0)
		:resLimit_(limit)
	{}
	~Semaphore() = default;

	// 获取一个信号量资源
	void wait()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		// 等待信号量有资源，没有资源的话，会阻塞当前线程
		cond_.wait(lock, [&]()->bool {return resLimit_ > 0; });
		resLimit_--;
	}

	// 增加一个信号量资源
	void post()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		resLimit_++;
		// linux下condition_variable的析构函数什么也没做
		// 导致这里状态已经失效，无故阻塞
		cond_.notify_all();  // 等待状态，释放mutex锁 通知条件变量wait的地方，可以起来干活了
	}
private:
	int resLimit_;
	std::mutex mtx_;
	std::condition_variable cond_;
};

//Task类型的前置声明
class Task;

// 实现接收提交到线程池的task任务执行完成后的返回值类型Result
class Result
{
public:
	Result(std::shared_ptr<Task> task, bool isValid = true);
	~Result() = default;

	// 问题一：setVal方法，获取任务执行完的返回值的
	void setVal(Any any);

	// 问题二：get方法，用户调用这个方法获取task的返回值
	Any get();
private:
	Any any_; // 存储任务的返回值
	Semaphore sem_; // 线程通信信号量
	std::shared_ptr<Task> task_; //强智能指针指向对应获取返回值的任务对象 
	std::atomic_bool isValid_; // 返回值是否有效
};

// 任务抽象基类
class Task
{
public:
	Task();
	~Task() = default;
	void exec();
	void setResult(Result* res);

	// 用户可以自定义任意任务类型，从Task继承，重写run方法，实现自定义任务处理
	virtual Any run() = 0;

private:
	Result* result_; // Result对象的声明周期 》 Task的
};



//线程池支持的模式
enum class PoolMode
{
	MODE_FIXED,//固定数量线程
	MODE_CACHED,//线程数量可动态增长
};

//线程类型
class Thread
{
public:
	/*std::function<void()> 是 C++ 标准库中
	std::function 模板的特化，代表 **“可调用对象” 的通用包装 **。
    void() 表示：这个可调用对象 “没有返回值（void ）、没有参数（空括号）” 。
	它能容纳函数指针、lambda 表达式、
    std::bind 绑定的函数、仿函数对象等，
	让这些不同形式的 “可调用逻辑” 能统一类型使用。
	using ThreadFunc = ... ：后续代码里，用 ThreadFunc 就能代替
	长长的 std::function<void()> ，让声明变量、函数参数更简洁。
	整句：给无参无返回值的可调用对象定义一个简洁的别名
	*/
	// 线程函数对象类型
	using ThreadFunc = std::function<void(int)>;

	// 线程构造
	Thread(ThreadFunc func);
	// 线程析构
	// 启动线程
	void start();

	// 获取线程id
	int getId()const;
private:
	ThreadFunc func_;
	static int generateId_;
	int threadId_;  // 保存线程id
};

/*
example:
ThreadPool pool;
pool.start(4);

class MyTask : public Task
{
	public:
		void run() { // 线程代码... }
};
//创建 MyTask 任务对象（智能指针管理），提交给线程池执行。
pool.submitTask(std::make_shared<MyTask>());
*/

//线程池类型
class  ThreadPool
{
public:
	ThreadPool();
	~ThreadPool();

	//设置线程池工作方式
	void setMode(PoolMode mode);

	//设置初始的线程数量
	//void setInitThredaSize();

	//设置task任务队列上限阈值
	void setTasQueMaxThreshHold(int threshhold);

	//设置线程池cached模式下线程上限阈值
	void setThreadSizeThreshHold(int threshhold);

	//给线程池提交任务
	Result submitTask(std::shared_ptr<Task> sp);

	//开启线程池
	void start(int initThreadSize = std::thread::hardware_concurrency());
	//cpu当前核心数量


	ThreadPool(const ThreadPool&) = delete;
	ThreadPool& operator=(const ThreadPool&) = delete;

	// 检查pool的运行状态
	bool checkRunningState() const;


private:
	//定义线程函数
	void threadFunc(int threadid);
	
	//检查pool的运行状态
	bool checkRunningState() const;

private:
	//指向线程 线程列表 这是一个基类指针 智能指针，在析构时可以把指针也delete
	//std::vector<std::unique_ptr<Thread>> threads_;//容器
	/*
	
	std::unordered_map：这是 C++ 标准库中的无序映射（哈希表）容器，
	它以键值对（key-value）的形式存储数据，查找、插入、删除等操作
	在这里，键（int 类型） 通常可用于标识线程（比如线程的唯一 ID ），
	值（std::unique_ptr<Thread> 类型） 
	是指向 Thread 对象的唯一智能指针，用于管理线程对象的生命周期 。
	***888888换成他的原因是因为线程结束的时候还要释放线程

	std::unique_ptr 是一种独占型智能指针，
	它保证同一时间只有一个 unique_ptr 指向同一个对象，
	转移所有权时（如赋值、传递等操作），原 unique_ptr 会失去对对象的所有权，
	新的 unique_ptr 获得所有权，这样可以有效避免资源的重复释放问题，
	帮助管理 Thread 对象的内存，防止内存泄漏 。
	当 unique_ptr 离开其作用域时，如果它还持有对象的所有权，
	会自动销毁所指向的 Thread 对象并释放相关内存
	*/
	std::unordered_map<int, std::unique_ptr<Thread>> threads_; // 线程列表
	int initThreadSize_;//初始的线程数量
	std::atomic_int curThreadSize_;//记录当前线程池里面线程的总数量
	int threadSizeThreshHold_;//线程队列数量阈值

	std::queue < std::shared_ptr<Task>> taskQue_;//智能指针指向任务队列
	std::atomic_int taskSize_;//任务的数量 线程安全的
	int taskQueMaxThreshHold_;//任务队列数量阈值

	std::mutex taskQueMtx_;//保证任务队列线程安全 
	std::condition_variable notFull_;//任务队列不满
	std::condition_variable notEmpty_;//任务队列不空 条件变量
	std::condition_variable exitCond_; // 等到线程资源全部回收

	PoolMode PoolMode_;//线程池工作方式
	//表示当前线程池的启动状态
	std::atomic_bool isPoolRunning_;
	std::atomic_int   idleThreadSize_;//记录空闲线程大小数量


};
#endif // 


